/*
 * Copyright 2011 www.pretty-tools.com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


#pragma once

#include "../XPCOMAdapter/XPCOMAdapter_i.h"
#include "ScriptConfiguration.h"
#include "Subscription.h"
#include "http/Connection.h"
#include "dllmain.h"

class RulesUpdateManager
{
private:
    RulesUpdateManager(void);

    class Profile : CComPtr<ILocalFile>
    {
    public:
        Profile(LPCWSTR pszName);

        bool Exists()
        {
            VARIANT_BOOL vbExists = VARIANT_FALSE;
            return p ? SUCCEEDED(p->exists(&vbExists)) && (VARIANT_TRUE == vbExists) : false;
        }

        CString GetPath()
        {
            CComBSTR bsPath;
            if (!p || FAILED(p->get_nativePath(&bsPath)) || !bsPath)
                return CString();

            return (CString)bsPath;
        }
    };

    template <typename T>
    class UpdateThread : protected Runnable
    {
    protected:
        CString m_strURL;
        CString m_strLastModified;

        UpdateThread()
        {
            _AtlModule.Lock();
        }

        ~UpdateThread()
        {
            _AtlModule.Unlock();
        }

        virtual void Run()
        {
            CoInitialize(0);

            HTTP::Connection con;

            CString strLastModified;
            if (!m_strLastModified.IsEmpty())
                strLastModified = (CString)_T("If-Modified-Since: ") + m_strLastModified + _T("\r\n");

            if (con.Open(m_strURL, strLastModified))
            {
                if (HTTP_STATUS_NOT_MODIFIED == con.GetStatusCode())
                    onData(CStringA(), m_strLastModified);
                else if (HTTP_STATUS_OK == con.GetStatusCode())
                {
                    CStringA strResponse;
                    if (!con.GetResponse(strResponse))
                        onData(CStringA(), CString());
                    else
                        onData(strResponse, con.GetLastModifiedHeader());
                }
                else
                {
                    onData(CStringA(), CString());
                }
            }

            CoUninitialize();
            delete ((T*)this);
        }

        virtual void onData(const CStringA& strData, const CString& strLastModified) = 0;

    public:
        void Start()
        {
            Thread().Create(this);
        }
    };

    class PredefinedProfileUpdateThread : public UpdateThread<PredefinedProfileUpdateThread>
    {
    public:
        PredefinedProfileUpdateThread()
        {
            Configuration wsshConfig;
            m_strURL = wsshConfig.urlPredefinedRules;
            m_strLastModified = wsshConfig.predefinedRulesLastModified;
        }

        virtual void onData(const CStringA& strData, const CString& strLastModified);
    };

    class SubscriptionUpdateThread : public UpdateThread<SubscriptionUpdateThread>
    {
    private:
        Subscription m_subscription;

    public:
        SubscriptionUpdateThread(const Subscription& subscription)
            : m_subscription(subscription)
        {
            m_strURL = m_subscription.url;
            m_strLastModified = m_subscription.lastModified;
        }

        virtual void onData(const CStringA& strData, const CString& strLastModified);
    };

    static Profile GetPredefinedProfile();
    static Profile GetSubscriptionProfile();
    static Profile GetProfile(LPCWSTR pszName);
    static COleDateTime ConvertStringToTime(LPCTSTR pszDate);

public:
    static void CheckForPredefinedRulesUpdate();
    static void CheckForSubscriptionUpdate(LPCTSTR pszSubscription);
};
